package com.hk.web.core.config.mybatis;

import org.aspectj.lang.annotation.Aspect;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


/**
 * 配置全局的事务
 */
@Configuration //声明配置类
@MapperScan("com.hk.dao.**.mapper") //spring与mybatis整合配置，扫描所有mapper
@Aspect
@EnableTransactionManagement // 启用注解事务管理，等同于 <tx:annotation-driven/>
@Order(3)
public class SpringTransactionConfig {

    private static final String AOP_POINTCUT_EXPRESSION = "execution(* *..service.*Service.*(..))";

    @Bean("txSource")
    public TransactionAttributeSource transactionAttributeSource() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        /*只读事务，不做更新操作*/
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        /*当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务*/
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED,
                Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
//        requiredTx.setTimeout(5);
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        txMap.put("save*", requiredTx);
        txMap.put("*Save", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("*Insert", requiredTx);
        txMap.put("add*", requiredTx);
        txMap.put("*Add", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("*Update", requiredTx);
        txMap.put("edit*", requiredTx);
        txMap.put("*Edit", requiredTx);
        txMap.put("delete*", requiredTx);
        txMap.put("*Delete", requiredTx);
        txMap.put("del*", requiredTx);
        txMap.put("*Del", requiredTx);
        txMap.put("payTransfer", requiredTx);
        txMap.put("*", readOnlyTx);
        source.setNameMap(txMap);
        return source;
    }

    /**
     * 切面拦截规则 参数会自动从容器中注入
     */
    @Bean
    public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor) {
        AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();
        pointcutAdvisor.setAdvice(txInterceptor);
        pointcutAdvisor.setExpression(AOP_POINTCUT_EXPRESSION);
        return pointcutAdvisor;
    }

    /**
     * 事务拦截器
     */
    @Bean("txInterceptor")
    TransactionInterceptor getTransactionInterceptor(TransactionManager txManager) {
        return new TransactionInterceptor(txManager, transactionAttributeSource());
    }

}
